#include "utils/Logger.h"
#include "entities/TowerControl.h"
#include "FlightGenerator.h"
#include <errno.h>
#include <iostream>
#include <getopt.h>
#include <stdio.h>
#include <sys/wait.h>

typedef struct Configuracion {
	unsigned int cantidadDeAviones;
	unsigned int cantidadDeControladores;
	unsigned int cantidadDePistas;
	std::string fileDebug;

	Configuracion() :
		cantidadDeAviones(1),
		cantidadDeControladores(1),
		cantidadDePistas(1),
		fileDebug("debug.txt"){};
};

Configuracion parseParams(int argc, char **argv);

int main(int argc, char **argv) {
	srand(time(NULL));
	Configuracion configuracion = parseParams(argc, argv);

	Logger log = Logger::instancia();

	log.setLogFile(configuracion.fileDebug.c_str());
	if ((configuracion.fileDebug.size() < 0) || log.open()){
		std::cout << "Error al abrir el archivo de log :" << configuracion.fileDebug << std::endl;
		exit(0);
	}

	pid_t pid;
	int status = -1;

	log << "Starting Airport Simulation pid:"<< getpid() <<eol;

	switch (pid = fork()) {
	case -1:
		log << "Fallo al realizar fork del proceso!"<<eol;
		perror("fork");
		Logger::close();
		return (-1);

	case 0: {
		log << "Main -Inicio Proceso Torre de control";
		TowerControl tc(configuracion.cantidadDePistas,configuracion.cantidadDeControladores);
		log << "Main -Corriendo Proceso Torre de control" <<eol;
		status = tc.run();
		log << "Main - FIN Proceso Torre de control"<<eol;
		Logger::close();
		return status;
	}

	default: {
		log<< "Main - Inicio Proceso FlightGenerator"<<eol;
		FlightGenerator generador(configuracion.cantidadDeAviones);
		generador.run();

		waitpid(pid, &status, 0);
		log<< "Main - FIN Proceso FlightGenerator"<<eol;
		Logger::close();
	}
	}

	log<< "Main - FIN Airport Simulation"<<eol;
	return status;
}

void showHelp() {
	std::cout << "Usage: flightSim "
			<< " [--help|-h] "
			<< " [--runways|-r=num] "
			<< " [--controllers|-c=num] "
			<< " [--flight|-f=num] "
			<< " [--debug-output|-o=FILE]" << std::endl;

	std::cout << "\t--help -h\t\tshow this help" << std::endl;
	std::cout
			<< "\t--runways -f=num\t\tset the number of runways to num (has to be greater or equal to 1)"
			<< std::endl;
	std::cout
			<< "\t--controllers -c=num\t\tset the number of controllers to num (has to be greater or equal to 1)"
			<< std::endl;
	std::cout
			<< "\t--flight -f=num\tset the number of flight to num (has to be greater than 0)"
			<< std::endl;
	std::cout << "\t--debug-output -o=FILE\tsave log message to the file"
			<< std::endl;
}

Configuracion parseParams(int argc, char **argv) {
	Configuracion configuracion;
	struct option long_options[] = {
			{ "help", no_argument, 0, 'h' },
			{ "runways", required_argument, 0, 'r' },
			{ "controllers", required_argument, 0, 'c' },
			{ "flight",required_argument, 0, 'f' },
			{ "debug-output", required_argument,0, 'o' },
			{ 0, 0,0, 0 }
	};
	int option_index = 0;
	int c = -1;

	while ((c = getopt_long(argc, argv, "h:r:c:f:o:", long_options,&option_index)) != -1) {
		switch (c) {
		case 'h':
			showHelp();
			exit(0);
		case 'c':
			if (sscanf(optarg, "%u", &configuracion.cantidadDeControladores) <= 0) {
				std::cout << "Invalid controller number: " << optarg << std::endl;
				exit(1);
			}
			if (configuracion.cantidadDeControladores < 2) {
				std::cout << "Invalid controller number ("
						<< configuracion.cantidadDeControladores
						<< ") should be greater than 1" << std::endl;
				exit(2);
			}
			break;
		case 'r':
			if (sscanf(optarg, "%u", &configuracion.cantidadDePistas) <= 0) {
				std::cout << "Invalid runways number: " << optarg << std::endl;
				exit(1);
			}
			if (configuracion.cantidadDePistas < 2) {
				std::cout << "Invalid runways number ("
						<< configuracion.cantidadDePistas
						<< ") should be greater than 1" << std::endl;
				exit(2);
			}
			break;
		case 'f':
			if (sscanf(optarg, "%u", &configuracion.cantidadDeAviones) <= 0) {
				std::cout << "Invalid flight number : " << optarg << std::endl;
				exit(1);
			}
			break;
		case 'o':
			configuracion.fileDebug = optarg;
			break;
		default:
			showHelp();
			perror("parse");
			exit(1);
		}
	}
	return configuracion;
}
